package com.affectu.common.base;

import java.io.InputStream;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;

import javax.faces.FactoryFinder;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 2008-8-10
 * 
 * @author daniel nathan
 * 
 *         Provides a common base class for all generated code behind files.
 */
public abstract class PageCodeBase extends UtilBase {
	protected FacesContext facesContext;
	protected Map<Object, Object> requestScope;
	protected Map<Object, Object> sessionScope;
	protected Map<Object, Object> applicationScope;
	protected Map<Object, Object> requestParam;

	protected FacesContext getFacesContext(HttpServletRequest request,
			HttpServletResponse response) {
		FacesContext facesContext = FacesContext.getCurrentInstance();

		if (facesContext == null) {

			FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder
					.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
			LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
					.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
			Lifecycle lifecycle = lifecycleFactory
					.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
			facesContext = contextFactory.getFacesContext(request.getSession()
					.getServletContext(), request, response, lifecycle);
		}
		return facesContext;

	}

	public boolean isAjaxRequest() {
		return (facesContext == null);
	}

	public void gotoPage(String pageName) {// ��
		if (pageName != null) {
			UIViewRoot newView = this.getFacesContext().getApplication()
					.getViewHandler().createView(this.getFacesContext(),
							pageName);
			this.getFacesContext().setViewRoot(newView);
		}
	}

	/**
	 * <p>
	 * Return the {@link UIComponent} (if any) with the specified
	 * <code>id</code>, searching recursively starting at the specified
	 * <code>base</code>, and examining the base component itself, followed by
	 * examining all the base component's facets and children. Unlike
	 * findComponent method of {@link UIComponentBase}, which skips recursive
	 * scan each time it finds a {@link NamingContainer}, this method examines
	 * all components, regardless of their namespace (assuming IDs are unique).
	 * 
	 * @param base
	 *            Base {@link UIComponent} from which to search
	 * @param id
	 *            Component identifier to be matched
	 */
	public static UIComponent findComponent(UIComponent base, String id) {

		// Is the "base" component itself the match we are looking for?
		if (id.equals(base.getId())) {
			return base;
		}

		// Search through our facets and children
		UIComponent kid = null;
		UIComponent result = null;
		Iterator<UIComponent> kids = base.getFacetsAndChildren();
		while (kids.hasNext() && (result == null)) {
			kid = (UIComponent) kids.next();
			if (id.equals(kid.getId())) {
				result = kid;
				break;
			}
			result = findComponent(kid, id);
			if (result != null) {
				break;
			}
		}
		return result;
	}

	public static UIComponent findComponentInRoot(String id) {
		UIComponent ret = null;

		FacesContext context = FacesContext.getCurrentInstance();
		if (context != null) {
			UIComponent root = context.getViewRoot();
			ret = findComponent(root, id);
		}

		return ret;
	}

	/**
	 * Place an Object on the tree's attribute map
	 * 
	 * @param key
	 * @param value
	 */
	protected void putTreeAttribute(String key, Object value) {
		getFacesContext().getViewRoot().getAttributes().put(key, value);
	}

	/**
	 * Retrieve an Object from the tree's attribute map
	 * 
	 * @param key
	 * @return
	 */
	protected Object getTreeAttribute(String key) {
		return getFacesContext().getViewRoot().getAttributes().get(key);
	}

	/**
	 * Return the result of the resolved expression
	 * 
	 * @param expression
	 * @return
	 */
	protected Object resolveExpression(String expression) {
		Object value = null;
		try {
			if ((expression.indexOf("#{") != -1)
					&& (expression.indexOf("#{") < expression.indexOf('}'))) {
				value = this.getFacesContext().getApplication()
						.getExpressionFactory().createValueExpression(
								this.getFacesContext().getELContext(),
								expression, Object.class).getValue(
								this.getFacesContext().getELContext());
			} else {
				value = expression;
			}
		} catch (Exception ex) {
			this.logException(ex);
			value = expression;
		}

		return value;
	}

	/**
	 * Resolve all parameters passed in via the argNames/argValues array pair,
	 * and add them to the provided paramMap<Object,Object>. If a parameter can
	 * not be resolved, then it will attempt to be retrieved from a cachemap
	 * stored using the cacheMap<Object,Object>Key
	 * 
	 * @param paramMap
	 *            <Object,Object>
	 * @param argNames
	 * @param argValues
	 * @param cacheMap
	 *            <Object,Object>Key
	 */
	@SuppressWarnings("unchecked")
	protected void resolveParams(Map<Object, Object> paramMap,
			String[] argNames, String[] argValues, String cacheMapKey) {

		Object rawCache = getTreeAttribute(cacheMapKey);
		Map<Object, Object> cache = Collections.emptyMap();
		if (rawCache instanceof Map) {
			cache = (Map<Object, Object>) rawCache;
		}
		for (int i = 0; i < argNames.length; i++) {
			Object result = resolveExpression(argValues[i]);
			if (result == null) {
				result = cache.get(argNames[i]);
			}
			paramMap.put(argNames[i], result);
		}
		putTreeAttribute(cacheMapKey, paramMap);
	}

	/**
	 * Returns a full system path for a file path given relative to the web
	 * project
	 */
	/*
	 * protected static String getRealPath(String relPath) { String path =
	 * relPath; try { URL url =
	 * FacesContext.getCurrentInstance().getExternalContext()
	 * .getResource(relPath); if (url != null) { path = url.getPath(); } } catch
	 * (MalformedURLException e) { e.printStackTrace(); } return path; }
	 */
	protected String getRealPath(String relPath) {
		String realPath = relPath;// 赋予初值
		try {
			HttpSession session = (HttpSession) this.getFacesContext()
					.getExternalContext().getSession(true);
			realPath = session.getServletContext().getRealPath(relPath);
		} catch (Exception ex) {
			this.logException(ex);
		}
		return realPath;
	}

	/**
	 * Returns an InputStream for a resource at the given path
	 */
	protected static InputStream getResourceInputStream(String relPath) {
		return FacesContext.getCurrentInstance().getExternalContext()
				.getResourceAsStream(relPath);
	}

	@SuppressWarnings("unchecked")
	public Map<Object, Object> getApplicationScope() {
		try {
			applicationScope = (Map<Object, Object>) this
					.resolveExpression("#{applicationScope}");
		} catch (Exception ex) {
			this.logException(ex);
		}
		return applicationScope;
	}

	public FacesContext getFacesContext() {
		return FacesContext.getCurrentInstance();
	}

	@SuppressWarnings("unchecked")
	public Map<Object, Object> getRequestParam() {
		try {
			requestParam = (Map<Object, Object>) this
					.resolveExpression("#{param}");
		} catch (Exception ex) {
			this.logException(ex);
		}
		return requestParam;
	}

	@SuppressWarnings("unchecked")
	public Map<Object, Object> getRequestScope() {
		try {
			requestScope = (Map<Object, Object>) this
					.resolveExpression("#{requestScope}");
		} catch (Exception ex) {
			this.logException(ex);
		}
		return requestScope;
	}

	@SuppressWarnings("unchecked")
	public Map<Object, Object> getSessionScope() {
		try {
			sessionScope = (Map<Object, Object>) this
					.resolveExpression("#{sessionScope}");
		} catch (Exception ex) {
			this.logException(ex);
		}
		return sessionScope;
	}

}